package openbee;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;

public class Communication implements ICommunication {

	private String _response;
	
	private List _listeners = new ArrayList();
	private JSch _jsch;
	private Properties _config;
	private Session _session;
	private int _interval = 1000;

	private InputStream in;
	private OutputStream out;

	private Channel _channel;
	private byte[] _tmpBuffer;
	
	private CommandArguments _commandArgs;
	private String _currentCommand;
	
	private CommandArguments _commandArgs2;
	
	public Communication() {
		_jsch = new JSch();
		_config = new Properties();
		_config.put("StrictHostKeyChecking", "no");
		_tmpBuffer = new byte[1024];
		_commandArgs = new CommandArguments();
		_commandArgs2 = new CommandArguments();
	}

	public void Connect(String ip, int port, String user, String password)
			throws JSchException {
		if (_session != null && _session.isConnected()) {
			throw new JSchException("Already connected!");
		} else {
			_session = _jsch.getSession(user, ip, port);
			_session.setConfig(_config);
			_session.setPassword(password);
			_session.connect();
		}

	}

	public void OpenChannel(String ip, String rotuerPort) {
		if (_session.isConnected()) {

			boolean isDataToRead = false;

			try {
				_channel = _session.openChannel("exec");
				((ChannelExec) _channel).setCommand("telnet " + ip + " " + rotuerPort);
				in = _channel.getInputStream();
				out = _channel.getOutputStream();
				((ChannelExec) _channel).setErrStream(System.err);
				_channel.connect();

				while (true) {
					_response = "";
					while (in.available() > 0) {
						int i = in.read(_tmpBuffer, 0, 1024);
						if (i < 0)
							break;
						
						_response += new String(_tmpBuffer, 0, i);
						isDataToRead = true;		
					}

					if (isDataToRead) {
						
						if (_response.endsWith("\r\n"))
						{
							if (_response.compareTo("\r\n") != 0)
							{
								if (_response.contains(_commandArgs2.get_command()))
									_commandArgs2.setSubmitted(true);	
							}	
						}
						// receive command without parsing
						if (!_response.startsWith("\r\n") && _response.endsWith("\r\n"))
							_commandArgs.setCommand(_currentCommand);
						
						if (_response.contains("MED") || _response.contains("FFD") || _response.contains("SED"))
							_commandArgs.setNewNode(true);
						
						_commandArgs.setPrompt(_response);
						
						_receivedResponse();
						
						isDataToRead = false;
					}
					
					Thread.sleep(_interval);
				}
			} catch (JSchException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

	public void CloseChannel() {
		if (_session.isConnected()) {
			_channel.disconnect();
		}
	}

	public synchronized void Send(String command) {
		try {
			
			//  
			_commandArgs2.setCommand(command);
			//
			
			_currentCommand = command;
			out.write((_commandArgs2.get_command() + "\r").getBytes());
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public synchronized void Disconnect() {

		if (_channel.isConnected())
			_channel.disconnect();

		_session.disconnect();
	}

	private synchronized void _receivedResponse() {
		
		ResponseEvent mood = new ResponseEvent(this, _commandArgs);
		Iterator listeners = _listeners.iterator();

		while (listeners.hasNext()) {
			((ResponseListener) listeners.next()).moodReceived(mood);
		}
	}
	

	public synchronized void addMoodListener(ResponseListener l) {
		_listeners.add(l);
	}

	/*
	 * private void awaitChannelClosure(ChannelExec channel) throws
	 * InterruptedException { while (channel.isConnected()) { Thread.sleep(100);
	 * // channel.setCommand("ATI" + "\n"); } }
	 * 
	 * private void closeQuietly(Closeable closeable) { if (closeable == null) {
	 * return; }
	 * 
	 * try { closeable.close(); } catch (IOException ignored) {
	 * ignored.printStackTrace(); } }
	 */
	
	
	/*private synchronized void _receivedCommand() {
	ResponseEvent mood = new ResponseEvent(this, _commandArgs);
	Iterator listeners = _listeners.iterator();

	// ((ResponseListener) listeners.next()).moodReceived(mood);
	while (listeners.hasNext()) {
		((ResponseListener) listeners.next()).moodReceived(mood);
	}
	}
 */

}
